﻿/*****************************************介绍*****************************************
 * 作者：Ywh
 * 创建时间：2023-04-12　11:28:45
 * 功能：数据校验实用类，提供各种数据校验的工具
**************************************************************************************/

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace Game.Framework.Utility
{
    public static class DataVerifyUtil
    {
        #region 键值对校验

        /// <summary>
        /// 校验来自服务端的值，如果校验不通过，则会返回给用户一个期望类型【T】的默认值，返回是否通过校验（isPass）和错误信息（errorStr）
        /// <para>注意：数字只能校验int、float类型</para>
        /// </summary>
        public static T VerifyProp<T>(Dictionary<string, object> props, string propName, out bool isPass, out string errorStr)
        {
            isPass = false;
            T result = default;
            errorStr = "";
            if (props == null)
            {
                errorStr = $"参数【props】为空";
                HandleUnexpected(ref errorStr, ref result);
                return result;
            }

            if (props.TryGetValue(propName, out object value))
            {
                if (value == null)
                {
                    errorStr = $"【{propName}】属性的值为Null";
                    HandleUnexpected(ref errorStr, ref result);
                }
                else
                {
                    try
                    {
                        result = (T)value;
                        isPass = true;
                    }
                    catch (Exception)
                    {
                        errorStr = $"无法将【{propName}】属性的值转换为【{typeof(T).Name}】类型";
                        HandleUnexpected(ref errorStr, ref result);
                    }
                }
            }
            else
            {
                errorStr = $"属性【{propName}】不存在";
                HandleUnexpected(ref errorStr, ref result);
            }
            return result;

            string GetFinalResultTipStr() => $"将使用【{(result == null ? "Null" : result)}】来代替！！";

            void HandleStringDefaultValue(ref T result)
            {
                if (typeof(T) == typeof(string))
                {
                    object value = string.Empty;
                    result = (T)value;
                }
            }

            void HandleUnexpected(ref string tip, ref T result)
            {
                HandleStringDefaultValue(ref result);
                tip = $"错误： {tip}，{GetFinalResultTipStr()}";
            }
        }

        /// <summary>
        /// 校验来自服务端的值，如果校验不通过，则会返回给用户一个期望类型【T】的默认值，返回是否通过校验（isPass）
        /// <para>注意：数字只能校验int、float类型</para>
        /// </summary>
        public static T VerifyProp<T>(Dictionary<string, object> props, string propName, out bool isPass)
        {
            return VerifyProp<T>(props, propName, out isPass, out _);
        }

        /// <summary>
        /// 校验来自服务端的值，如果校验不通过，则会返回给用户一个期望类型【T】的默认值
        /// <para>注意：数字只能校验int、float类型</para>
        /// </summary>
        public static T VerifyProp<T>(Dictionary<string, object> props, string propName)
        {
            return VerifyProp<T>(props, propName, out _, out _);
        }

        #endregion

        #region 字符校验

        /// <summary>由汉字、字母、数字组成的字符串</summary>
        public const string PATTERN1 = @"^[a-zA-Z0-9\u4E00-\u9FA5]+$";

        /// <summary>匹配所有汉字</summary>
        public const string PATTERN2 = @"[\u4E00-\u9FA5]";

        /// <summary>判断整个内容是否由数字字母下划线组成</summary>
        public const string PATTERN3 = @"^[a-zA-z_0-9]+$";

        public static bool IsMatch(string source, string pattern)
        {
            if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
            {
                LogManager.Log($"目标字符串或匹配模式不能为空");
                return false;
            }
            return Regex.IsMatch(source, pattern);
        }

        public static string MatchingAll(string source, string pattern)
        {
            if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
            {
                LogManager.Log($"目标字符串或匹配模式不能为空");
                return "";
            }
            StringBuilder result = new StringBuilder();
            MatchCollection matches = Regex.Matches(source, pattern);
            foreach (Match item in matches)
            {
                result.Append(item.Value);
            }
            return result.ToString();
        }

        public static int GetCharacterRealityLength(string source)
        {
            if (string.IsNullOrEmpty(source))
            {
                LogManager.Log($"目标字符串不能为空");
                return -1;
            }
            return Encoding.UTF8.GetByteCount(source);
        }

        /// <summary>
        /// 名称合法性校验
        /// <para>合法条件1：内容只能包含：数字、字母、汉字</para>
        /// <para>合法条件2：字符数数量位于：6~12之间，一个汉字代表2字符，其他代表1字符</para>
        /// </summary>
        /// <returns>校验通过：true，否则：false</returns>
        public static bool CharacterLimit(string str, out string error)
        {
            int limitMax = 12;
            int limitMin = 4;
            error = "内容不可以为空或者内容格式不正确，只能输入：数字、字母、汉字！！";
            if (string.IsNullOrEmpty(str)) return false;
            if (Regex.IsMatch(str, PATTERN1))
            {
                int chineseCharCount = Regex.Matches(str, PATTERN2).Count;
                int curCount = chineseCharCount == 0 ? str.Length : chineseCharCount * 2 + (str.Length - chineseCharCount);
                if (curCount < limitMin || curCount > limitMax)
                {
                    error = $"字符数量不达标，限制在{limitMin}~{limitMax}之间，一个汉字代表2个字符，其余为1个字符！！";
                    return false;
                }
                error = "";
                return true;
            }
            return false;
        }

        #endregion

        /// <summary>获取指定类的所有的内部类（该内部类继承自指定类型）</summary>
        /// <typeparam name="SignT">内部类的类型</typeparam>
        /// <typeparam name="ParentT">目标类型的父类</typeparam>
        public static List<Type> GetInternalAllSignSubType<SignT, ParentT>() where SignT : class where ParentT : class
        {
            Type[] allTypes = typeof(SignT).GetNestedTypes(BindingFlags.NonPublic);
            List<Type> result = new List<Type>();
            foreach (Type innrType in allTypes)
            {
                if (innrType.IsSubclassOf(typeof(ParentT)))
                    result.Add(innrType);
            }
            return result;
        }
    }
}
